﻿/***************获取身份证信息*****************
 * 通过15位或者18位身份证号计算：生日、性别、地区
 *********************************************/

namespace LSLib.LSL
{
    using LSLib.Collections;
    using System;
    using System.Text.RegularExpressions;

    public class GetIDCardInfoCls
    {
        /// <summary>结构体：身份证信息
        /// </summary>
        public struct IDCardInfos
        {
            public DateTime Birthday;
            public string Sex;
            public string District_Simple;
            public string District_Full;
        }

        /// <summary>分析身份证号，返回：生日、性别、地区(简)、地区(全)
        /// </summary>
        /// <param name="strIDNum">身份证号字符串</param>
        /// <returns>返回IDCardInfos结构的身份证信息</returns>
        public IDCardInfos AnalyzeIDCard(string strIDNum)
        {
            if (string.IsNullOrEmpty(strIDNum))
                throw new ArgumentNullException("strIDNum");
            if (strIDNum.Length != 15 && strIDNum.Length != 18)
                throw new ArgumentException("身份证号长度不正确！");

            this.checkIDCardByRegex(strIDNum);
            this.checkIDCardByHeadAB(strIDNum);
            this.checkIDCardByParseBirthday(strIDNum);

            return this.getIDCardInfo(strIDNum);
        }

        #region CheckBefore
        /// <summary>用正则表达式去校验身份证号的输入
        /// </summary>
        private void checkIDCardByRegex(string IDCardNo)
        {
            string rule = string.Empty;

            if (IDCardNo.Length == 15)
                rule = @"\d{6}\d{2}[0-1]\d[0-3]\d{4}";
            else if (IDCardNo.Length == 18)
                rule = @"\d{6}[1-2]\d{3}[0-1]\d[0-3]\d{4}[0-9X]";

            System.Text.RegularExpressions.Regex regex = new Regex(rule);
            if (!regex.IsMatch(IDCardNo)) throw new ArgumentException("身份证号格式不正确！");
        }

        /// <summary>判断前两位数字是否为正确的地区代码
        /// </summary>
        private void checkIDCardByHeadAB(string IDCardNo)
        {
            string headAB = IDCardNo.Substring(0, 2);
            //若前两位数字在地区代码中不存在，则为假
            if (DistrictCodeTable.GetDistrictTable_Simple().Contains(headAB) == false)
                throw new ArgumentException("身份证号的地区代码不存在！");
        }

        /// <summary>出生日期是否可转换
        /// </summary>
        private void checkIDCardByParseBirthday(string IDCardNo)
        {
            //更改15位身份证中的日期格式
            if (IDCardNo.Length == 15) IDCardNo = IDCardNo.Insert(6, "19");

            string testBir = IDCardNo.Substring(6, 8).Insert(4, "-").Insert(7, "-");
            System.DateTime testRes;
            System.DateTime.TryParse(testBir, out testRes);

            //若转换结果为最小值，这说明转换失败
            if (testRes == System.DateTime.MinValue)
                throw new ArgumentException("15位身份证号格式不正确！");
        }
        #endregion

        #region 私有函数
        /// <summary>获取身份证信息
        /// </summary>
        /// <returns>生日、性别、地区(简)、地区(全)</returns>
        private IDCardInfos getIDCardInfo(string IDCardNo)
        {
            //格式化身份证号
            IDCardNo = this.formatIDCardNo(IDCardNo);

            IDCardInfos info = new IDCardInfos();

            info.Birthday = this.getBirthday(IDCardNo);              //生日
            info.Sex = this.getSexName(IDCardNo);                    //性别
            info.District_Simple = this.getDistrict_Simple(IDCardNo);//地区(简)
            info.District_Full = this.getDistrict_Full(IDCardNo);    //地区(全)

            return info;
        }

        /// <summary>格式化身份证号
        /// </summary>
        private string formatIDCardNo(string IDCardNo)
        {
            string result = IDCardNo;

            //更改15位身份证中的日期格式
            if (IDCardNo.Length == 15) result = IDCardNo.Insert(6, "19");

            return result;
        }

        /// <summary>获取出生日期
        /// </summary>
        private DateTime getBirthday(string IDCardNo)
        {
            string bir = IDCardNo.Substring(6, 8).Insert(4, "-").Insert(7, "-");
            return System.DateTime.Parse(bir);
        }

        /// <summary>获取性别名称
        /// </summary>
        private string getSexName(string IDCardNo)
        {
            int sex = int.Parse(IDCardNo.Substring(16, 1));
            return (sex % 2 == 1) ? "男" : "女";
        }

        /// <summary>获取地区名简称
        /// </summary>
        private string getDistrict_Simple(string IDCardNo)
        {
            return DistrictCodeTable.GetDistrictCode(IDCardNo.Substring(0, 2), DistrictCodeTable.ResultType.Simple);
        }

        /// <summary>获取地区名全称
        /// </summary>
        private string getDistrict_Full(string IDCardNo)
        {
            return DistrictCodeTable.GetDistrictCode(IDCardNo.Substring(0, 2), DistrictCodeTable.ResultType.Full);
        }
        #endregion
    }
}